package com.algoshow.controller;

import com.algoshow.model.TreeNode;
import com.algoshow.view.FirstMenu;
import com.algoshow.view.SecondMenu;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;

/**
 * @author vvv
 * @date 2023-05-19 13 30
 * discription
 */
public class TreePage extends BasePage {

    private TreeNode root;
    private Integer depth = 0;

    private static final int NODE_SIZE = 50 + 20;  // 节点大小 50
    private static final int HORIZONTAL_GAP = 80 + 80; // 节点之间的水平间距 80
    private static final int VERTICAL_GAP = 100 + 40;   // 节点之间的垂直间距 100

    // 非递归栈
    private Stack<TreeNode> stack = new Stack<>();

    public TreePage(TreeNode root, String algoName) throws HeadlessException {
        this.root = root;
        this.algoName = algoName;
        firstMenuButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (timer != null && timer.isAlive()) {
                    timer.stop();
                }
                dispose();
                new SecondMenu().showTest3();
            }
        });
    }

    @Override
    public void drawAlgo(Graphics g) {
        if (root != null) {
            // 计算根节点的位置
            int x = getWidth() / 2 - NODE_SIZE / 2 - 500;
            int y = 300;
            // 绘制根节点
            drawNode(g, root, x, y, HORIZONTAL_GAP);
        }
        if (algoName.startsWith("stack")) {
            // TODO 这里的坐标有点问题
            drawStack(g);
            drawStackNode(g);
        }
    }

    @Override
    public void drawParam(Graphics g) {
        // 坐标
        int x = paramX, y = paramY;
        if (algoName.startsWith("stack")) {
            g.drawString("stack_size = ", x, y);
            g.drawString(String.valueOf(stack.size()), x + 200, y);
        } else {
            g.drawString("depth = ", x, y);
            g.drawString(depth.toString(), x + 120, y);
        }
    }

    // TODO 画入栈的元素
    private void drawStackNode(Graphics g) {
        Font font = new Font("Arial", Font.BOLD, 40);
        g.setFont(font);
        for (int i = 0; i < stackNodes.size(); i++) {
            Node node = stackNodes.get(i);
            if (node.value == -1) {
                g.drawString("null", node.x, node.y);
            } else {
                g.drawString(node.value.toString(), node.x, node.y);
            }
        }
    }

    private void drawNode(Graphics g, TreeNode node, int x, int y, int horizontalGap) {
        // 绘制节点
        g.setColor(node.color);
        g.fillOval(x, y, NODE_SIZE, NODE_SIZE);
        g.setColor(Color.BLACK);
        g.drawString(Integer.toString(node.value), x + 20 + 10, y + 30 + 10);


        // 绘制左子节点和连接线
        if (node.left != null) {
            int childX = x - horizontalGap;
            int childY = y + VERTICAL_GAP;
            g.drawLine(x + NODE_SIZE / 2, y + NODE_SIZE, childX + NODE_SIZE / 2, childY);
            drawNode(g, node.left, childX, childY, horizontalGap / 2);
        }

        // 绘制右子节点和连接线
        if (node.right != null) {
            int childX = x + horizontalGap;
            int childY = y + VERTICAL_GAP;
            g.drawLine(x + NODE_SIZE / 2, y + NODE_SIZE, childX + NODE_SIZE / 2, childY);
            drawNode(g, node.right, childX, childY, horizontalGap / 2);
        }
    }


    public void drawStack(Graphics g) {

        int width = 100 + 20;  // 长方形的宽度
        int height = 600; // 长方形的高度
        int borderWidth = 5; // 边框宽度
        int x = 900; // 给定的x坐标
        int y = 150; // 给定的y坐标

        // 计算边框位置
        int borderX = x - borderWidth;
        int borderY = y;
        int borderHeight = height - y;

        // 绘制边框
        g.setColor(Color.BLACK);
        g.fillRect(borderX, borderY, borderWidth, borderHeight); // 左边框
        g.fillRect(borderX + width - borderWidth, borderY, borderWidth, borderHeight); // 右边框
        //g.fillRect(borderX, borderY, width, borderWidth); // 上边框
        g.fillRect(borderX, borderY + borderHeight - borderWidth, width, borderWidth); // 底边框
    }

    @Override
    public void startThread() {
        timer = new Thread() {
            @Override
            public void run() {
                switch (algoName) {
                    case "preorder":
                        preorder(root);
                        break;
                    case "inorder":
                        inorder(root);
                        break;
                    case "postorder":
                        preorder(root);
                        break;
                    case "levelorder":
                        levelorder(root);
                        break;
                    case "stackPreorder":
                        stackPreorder(root);
                        break;
                    case "stackInorder":
                        stackInorder(root);
                        break;
                    case "stackPostorder":
                        stackPostOrder(root);
                        break;
                    default:
                        timer.stop();
                }
            }

        };
        timer.start();
    }

    //  TODO 层序　
    private void levelorder(TreeNode root) {
        render(0);
        Queue<TreeNode> q = new LinkedList<>();
        render(1);
        render(2,100);
        q.add(root);
        render(3);
        while (!q.isEmpty()) {
            render(4);
            int size = q.size();
            render(5);
            depth += 1;
            for (int i = 0; i < size; i++) {
                render(6);
                TreeNode node = q.poll();
                node.color = GREEN;
                render(7);
                render(8);
                if (node.left != null) {
                    render(9,200);
                    q.add(node.left);
                }
                render(10);
                if (node.right != null) {

                    render(11,200);
                    q.add(node.right);
                }
            }
        }
    }

    //前序
    private void preorder(TreeNode root) {
        render(1);
        if (root == null) {
            render(2);
            return;
        }
        render(4);
        root.color = GREEN;
        depth++;
        render(5);
        preorder(root.left);
        depth--;
        render(6);
        depth++;
        preorder(root.right);
        depth--;
    }

    // 中序
    private void inorder(TreeNode root) {
        render(1);
        if (root == null) {
            render(2);
            return;
        }
        depth++;
        render(4);
        inorder(root.left);
        depth--;
        render(null, 900);
        root.color = red;
        System.out.println(root.value);
        render(5);
        depth++;
        render(6);
        inorder(root.right);
        depth--;
        render(null, 900);
    }

    // 后序
    private void postorder(TreeNode root) {
        render(1);
        if (root == null) {
            render(2);
            return;
        }
        depth++;
        render(4);
        postorder(root.left);
        depth--;
        render(5);
        depth++;
        render(null, 900);
        postorder(root.right);
        depth--;
        render(6);
        root.color = GREEN;
        System.out.println(root.value);
    }

    // 前序非递归
    private void stackPreorder(TreeNode root) {
        render(1);
        myPush(root);
        while (!stack.isEmpty()) {
            render(2,300);
            render(3);
            TreeNode node = myPop();
            render(4,300);
            if (node != null) {
                // right
                render(5,300);
                if (node.right != null) {
                    render(6,300);
                    myPush(node.right);
                }
                // left
                render(7,300);
                if (node.left != null) {
                    render(8,300);
                    myPush(node.left);
                }
                // mid
                render(9,300);
                myPush(node);
                render(10,300);
                myPush(null);

            } else {
                render(11, 300);
                TreeNode temp = myPopNotMove();
                temp.color = GREEN;
                System.out.println("test" + temp.value);
                render(12);
            }
        }
    }

    // TODO 中序非递归
    private void stackInorder(TreeNode root) {
        render(1);
        myPush(root);
        while (!stack.isEmpty()) {
            render(2,300);
            render(3);
            TreeNode node = myPop();
            render(4,300);
            if (node != null) {
                // right
                render(5,300);
                if (node.right != null ) {
                    render(6,300);
                    myPush(node.right);
                }
                // mid
                render(7,300);
                myPush(node);
                render(8,300);
                myPush(null);

                // left
                render(9,300);
                if (node.left != null) {
                    render(10,300);
                    myPush(node.left);
                }
            } else {
                render(11, 300);
                TreeNode temp = myPopNotMove();
                temp.color = GREEN;
                System.out.println("test" + temp.value);
                render(12);
            }
        }
    }

    // TODO 后续非递归
    private void stackPostOrder(TreeNode root) {
        render(1);
        myPush(root);
        while (!stack.isEmpty()) {
            render(2, 300);
            render(3);
            TreeNode node = myPop();
            render(4, 300);
            if (node != null) {
                render(5,300);
                // mid
                myPush(node);
                render(6,300);
                myPush(null);
                // right
                render(7,300);
                if (node.right != null) {
                    render(8,300);
                    myPush(node.right);
                }
                // left
                render(9,300);
                if (node.left != null) {
                    render(10,300);
                    myPush(node.left);
                }
            } else {
                render(11, 300);
                TreeNode temp = myPopNotMove();
                temp.color = GREEN;
                System.out.println("test" + temp.value);
                render(12);
            }
        }
    }

    private class Node {
        Integer value;
        Integer x;
        Integer y;

        public Node() {
        }

        public Node(Integer value, Integer x, Integer y) {
            this.value = value;
            this.x = x;
            this.y = y;
        }
    }


    private List<Node> stackNodes = new LinkedList<>();

    // 元素入栈的坐标
    private int stackX = 900 + 30;
    private int stackY = 200 + 300 + 50;
    private int offset = 50;

    public void myPush(TreeNode node) {
        // node 入栈
        stack.add(node);
        // 判断是否为null
        int value = node == null ? -1 : node.value;
        stackNodes.add(new Node(value, stackX, stackY));
        stackY -= offset;
        render();
    }

   public TreeNode myPop() {
       TreeNode node = stack.pop();
       Node stackNode = stackNodes.get(stackNodes.size() - 1);
       move(stackNode, stackNode.x, stackNode.y - 500, 10);
       stackNodes.remove(stackNodes.size() - 1);
       stackY += offset;
       return node;
   }

   public TreeNode myPopNotMove() {
       TreeNode node = stack.pop();
       stackNodes.remove(stackNodes.size() - 1);
       render(null, 500);
       stackY += offset;
       return node;
    }

    // 移动动画
    public void move(Node node, int endX, int endY, int speed) {
        while (node.x != endX || node.y != endY) {
            if (node.x < endX) {
                node.x += speed;
            } else if (node.x > endX) {
                node.x -= speed;
            }

            if (node.y < endY) {
                node.y += speed;
            } else if (node.y > endY) {
                node.y -= speed;
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            panel.repaint();
        }
        try {
            Thread.sleep(50);
        } catch (Exception e) {
            new RuntimeException(e);
        }
    }
}
